// @Author EthanScriptOn
// @Desc
package initialization

import (
	"errors"
	"gitee.com/fatzeng/srf_switch_basic_components/identity"
	"gitee.com/fatzeng/srf_switch_basic_components/resource"
	"time"
)

// InitializerFunc Initialize the function definition
type InitializerFunc func() (result interface{}, err error)

// upGradationResourceManager Use a multi-level resource manager to manage initialization functions
var upGradationResourceManager = resource.GenerateResourceManagerUpGradationMultiLevel()

// identityInformationStrategy Customize the identity information of the initialization function
var identityInformationStrategy = func() identity.IdentityInformation {
	snowflake, err := identity.GenerateSnowflake(&identity.SnowflakeConfig{Epoch: time.Now(), SequenceBits: 12})
	if err != nil {
		panic(err)
	}
	return identity.GeneratePrefixedObjectId(snowflake, "once_initializer")
}()

// initFuncWrapper The wrapper of the initialization function, adapted to the resource manager
type initFuncWrapper struct {
	identity.IdentityInformation
	initFunc    InitializerFunc
	initTag     InitTag
	positionTag PositionTag
	priority    int
}

// IsValid Whether it is a valid initialization function
func (i *initFuncWrapper) IsValid() (err error) {
	if i.positionTag == "" {
		return errors.New("the location identifier cannot be empty")
	}
	if i.initTag == "" {
		return errors.New("the initTag cannot be empty")
	}
	if i.initFunc == nil {
		return errors.New("the initFunc cannot be empty")
	}
	return
}

// Priority The priority of the initialization function
// can be relied on by the resource manager to admit the best by priority
func (i *initFuncWrapper) Priority() int {
	return i.priority
}

// AddInitializerFunc Add an initialization function
func AddInitializerFunc(positionTag PositionTag, initTag InitTag, priority int, initFunc InitializerFunc, cover bool) error {
	return upGradationResourceManager.AddResource(&initFuncWrapper{
		IdentityInformation: identityInformationStrategy,
		initFunc:            initFunc,
		positionTag:         positionTag,
		initTag:             initTag,
		priority:            priority,
	}, []resource.ResourceLevel{resource.ResourceLevel(positionTag), resource.ResourceLevel(initTag)}, cover)
}

// GetInitializerFunc Get an initialization function
func GetInitializerFunc(positionTag PositionTag, initTag InitTag) (InitializerFunc, error) {
	result, err := upGradationResourceManager.FoundResourceWithLevels([]resource.ResourceLevel{resource.ResourceLevel(positionTag), resource.ResourceLevel(initTag)})
	if err != nil {
		return nil, err
	}
	if len(result) <= 0 {
		return nil, nil
	}
	return result[0].(*initFuncWrapper).initFunc, nil
}
